package org.dromara.common.satoken.handler;

import cn.dev33.satoken.exception.NotLoginException;
import cn.dev33.satoken.exception.NotPermissionException;
import cn.dev33.satoken.exception.NotRoleException;
import cn.hutool.http.HttpStatus;
import jakarta.servlet.http.HttpServletRequest;
import lombok.extern.slf4j.Slf4j;
import org.dromara.common.core.domain.R;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;


/**
 * @Author 刘武贵
 * @Date 2024/8/15 22:00
 * @Description 功能描述：SaToken异常处理器
 */
@Slf4j
/**
 * 定义一个全局异常处理器，用于处理应用程序中抛出的所有异常。
 * 通过使用 @RestControllerAdvice 注解，该类能够集中处理所有 REST 控制器中的异常，
 * 并将异常信息转换为 HTTP 响应返回给客户端。
 */
@RestControllerAdvice
public class SaTokenExceptionHandler {

    /**
     * 权限码异常
     * 处理未授权异常
     * 当用户尝试访问其没有权限的资源时，会调用此方法
     * 它记录了异常信息，并返回一个表示没有访问权限的响应
     *
     * @param e            未授权异常对象，包含具体的权限验证失败信息
     * @param request      HTTP请求对象，用于获取请求的URI
     * @return             返回一个R对象，其中包含失败的状态码和没有访问权限的提示信息
     */
    @ExceptionHandler(NotPermissionException.class)
    public R<Void> handleNotPermissionException(NotPermissionException e, HttpServletRequest request) {
        String requestURI = request.getRequestURI();
        log.error("请求地址'{}',权限码校验失败'{}'", requestURI, e.getMessage());
        return R.fail(HttpStatus.HTTP_FORBIDDEN, "没有访问权限，请联系管理员授权");
    }

    /**
     * 角色权限异常
     * 处理未授权异常
     * 当用户尝试访问其角色没有权限访问的资源时，会调用此方法
     * 它记录了请求的URI和异常信息，并返回一个包含禁止状态和错误消息的结果
     *
     * @param e           抛出的NotRoleException异常对象
     * @param request     HTTP请求对象，用于获取请求的URI
     * @return            返回一个R对象，包含处理结果，这里总是失败的结果，因为权限校验失败
     */
    @ExceptionHandler(NotRoleException.class)
    public R<Void> handleNotRoleException(NotRoleException e, HttpServletRequest request) {
        String requestURI = request.getRequestURI();
        log.error("请求地址'{}',角色权限校验失败'{}'", requestURI, e.getMessage());
        return R.fail(HttpStatus.HTTP_FORBIDDEN, "没有访问权限，请联系管理员授权");
    }

    /**
     * 认证失败
     * 处理未登录异常
     * 当用户未登录而尝试访问需要认证的资源时，会抛出NotLoginException
     * 此方法用于捕获该异常并返回相应的错误信息
     *
     * @param e 异常对象，包含具体的错误信息
     * @param request HttpServletRequest对象，用于获取当前请求的URI
     * @return 返回一个R类型的对象，包含错误状态码和错误信息
     */
    @ExceptionHandler(NotLoginException.class)
    public R<Void> handleNotLoginException(NotLoginException e, HttpServletRequest request) {
        String requestURI = request.getRequestURI();
        log.error("请求地址'{}',认证失败'{}',无法访问系统资源", requestURI, e.getMessage());
        return R.fail(HttpStatus.HTTP_UNAUTHORIZED, "认证失败，无法访问系统资源");
    }

}
